<?php

namespace Ku;

final class Sudoers {
    
    protected static $_instance = null;
    protected $_cKey   = 'sudoer.pool';
    protected $_value  = null;
    protected $_name   = null;
    protected $_keep   = 1440;
    protected $_expire = 1800; // keep < expire
    
    /**
     * 同一进程请求范围内保证HASH一致性
     *
     * @var string 
     */
    protected $_hash = null;
    
    /**
     * 用户特征码
     *
     * @var string 
     */
    protected $_usersSignature = null;

    /**
     * 同一进程请求范围内仅处理一次COOKIE写操作
     *
     * @var boolean 
     */
    protected $_onlyCookie = true;

    private function __construct() {}
    private function __clone() {}
    private function __sleep() {}

    /**
     * @return \Lib\Sudoers
     */
    public static function getInstance() {
        if (!self::$_instance instanceof self) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }
    
    /**
     * 语法糖 setName & setValue && push
     * 
     * @param string $name
     * @param string $value
     * @return \Lib\Sudoers
     */
    public function set($name, $value) {
        $this->setName($name);
        $this->setValue($value);
        $this->push();
        
        return true;
    }
    
    /**
     * 语法糖 setName && pull
     * 
     * @param string $name
     * @return string
     */
    public function get($name) {
        return $this->setName($name)->pull();
    }
    
    /**
     * 语法糖 setName && remove
     * 
     * @param string $name
     * @return string
     */
    public function del($name) {
        return $this->setName($name)->remove();
    }

    /**
     * sudoer name
     * 
     * @param string $name
     * @return \Lib\Sudoer
     */
    public function setName($name) {
        $this->_name = (string)$name;
        
        return $this;
    }
    
    /**
     * sudoer name value
     * 
     * @param string $value
     * @return \Lib\Sudoer
     */
    public function setValue($value) {
        $this->_value = (string)$value;
        
        return $this;
    }
    
    /**
     * KEEP 保持时长(s)
     * 
     * @param int $keep
     * @return \Lib\Sudoer
     */
    public function setKeep($keep) {
        $this->_keep = $keep;
        
        return $this;
    }
    
    /**
     * 过期时间
     * 
     * @param int $expire
     * @return \Lib\Sudoer
     */
    public function setExpire($expire) {
        $this->_expire = (int)$expire > 1800 ? $expire : 1800;
        
        return $this;
    }

    /**
     * 加入sudoer pool
     * 
     * @return boolean
     */
    public function push() {
        $redis = $this->getRedis();
        $key   = $this->_cKey;
        $now   = time();
        
        $redis->hSet($key, $this->getFeildOfName(), $this->_value);
        $redis->hSet($key, $this->getFeildOfTime(), $now + $this->_keep);
        $redis->expireAt($key, $now + $this->_expire);
        $this->cookie();
        $this->reset();
        
        return true;
    }
    
    /**
     * 获取某个sudoer 
     * 
     * @return string
     */
    public function pull() {
        $redis = $this->getRedis();
        $key   = $this->_cKey;
        $ret   = null;
        
        if($redis->hGet($key, $this->getFeildOfTime()) > time()) {
            $ret = $redis->hGet($key, $this->getFeildOfName());
        }
        
        return $ret;
    }
    
    /**
     * 移除某个sudoer 
     * 
     * @return boolean
     */
    public function remove() {
        $redis = $this->getRedis();
        $key   = $this->_cKey;
        
        $redis->hDel($key, $this->getFeildOfName());
        $redis->hDel($key, $this->getFeildOfTime());
        
        return true;
    }
    
    /**
     * 重置
     */
    public function reset() {
        $this->_value  = null;
        $this->_name   = null;
        
        return true;
    }

    /**
     * 获取name的filed HASH
     * 
     * @return string
     */
    protected function getFeildOfName() {
        return sha1($this->_name . '_' . $this->getHash() . '_name#' . $this->getUsersSignature());
    }
    
    /**
     * 获取time的filed HASH
     * 
     * @return string
     */
    protected function getFeildOfTime() {
        return sha1($this->_name . '_' . $this->getHash() . '_time#' . $this->getUsersSignature());
    }
    
    /**
     * 用户特征码 Hash
     * 
     * @return string
     */
    protected function getUsersSignature() {
        if(empty($this->_usersSignature)) {
            $code = array();
            $code[] = \Lib\Tool::getClientIp();
            $code[] = \filter_input(\INPUT_SERVER, 'HTTP_USER_AGENT');
            
            $this->_usersSignature = sha1(implode('.', $code));
        }
        
        return $this->_usersSignature;
    }

    /**
     * @return \Redis
     */
    protected function getRedis() {
        return \Yaf\Registry::get('redis');
    }
    
    /**
     * 设置COOKIE
     * 
     * @return boolean
     */
    protected function cookie() {
        $hash = $this->getHash();

        if(empty($hash) && $this->_onlyCookie === true) {
            setcookie('_umtcsn', $this->getHash(false), time() + $this->_keep, '/', null, false, true);
            $this->_onlyCookie = false;
        }
        
        return true;
    }
    
    /**
     * @param boolean $onlyRead
     * @return string
     */
    protected function getHash($onlyRead = true) {
        if(empty($this->_hash)) {
            $this->_hash = \filter_input(\INPUT_COOKIE, '_umtcsn', \FILTER_SANITIZE_STRING);

            if(empty($this->_hash) && $onlyRead === false) {
                $uniqidVal = uniqid(mt_rand(100000, 9999999));
                
                $this->_hash = sha1($uniqidVal . '@' . microtime(true) . '#' . $this->_expire);
            }
        }
        
        return $this->_hash;
    }
}